﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;

namespace MyRecipeBook.Classes
{
    public class Conversions
    {
        public string LastException { get; private set; }

        public Status Add(int fromType, float fromAmount, int toType, float toAmount)
        {

            if (fromType == toType) 
                return new Status { Result = StatusResult.Error, Code = StatusCode.ConversionTypesAreSame };
            if (fromType == 0) 
                return new Status { Result = StatusResult.Error, Code = StatusCode.ConversionFromTypeIsInvalid };
            if (toType == 0) 
                return new Status { Result = StatusResult.Error, Code = StatusCode.ConversionToTypeIsInvalid };
            if (fromAmount <= 0f)
                return new Status { Result = StatusResult.Error, Code = StatusCode.ConversionFromAmountIsLessThanOrZero };
            if (toAmount <= 0f) 
                return new Status { Result = StatusResult.Error, Code = StatusCode.ConversionToAmountIsLessThanOrZero };
            
            MeasurementType mt;
            var m = new Measurements();
            switch (m.GetMeasurementType(fromType, out mt).Result)
            {
                case StatusResult.Success:
                    if (mt != MeasurementType.Weight)
                        return new Status {Result = StatusResult.Error, Code = StatusCode.ConversionFromTypeIsInvalid};
                    break;
                default:
                    return new Status {Result = StatusResult.Error, Code = StatusCode.MeasurementTypeUnknown};
            }

            switch (m.GetMeasurementType(toType, out mt).Result)
            {
                case StatusResult.Success:
                    if (mt != MeasurementType.Weight)
                        return new Status { Result = StatusResult.Error, Code = StatusCode.ConversionToTypeIsInvalid };
                    break;
                default:
                    return new Status { Result = StatusResult.Error, Code = StatusCode.MeasurementTypeUnknown };
            }

            Conversion conv;
            var status = GetConversion(fromType, toType, out conv);

            if (status.Code == StatusCode.ConversionNotFound)
            {
                //check that the opposite definition doesnt exist - if it does check the reverse calculation is good
                if (GetConversion(toType, fromType, out conv).Code == StatusCode.ConversionFound)
                {
                    return new Status { Result = StatusResult.Failed, Code = StatusCode.ConversionAlreadyExists };
                }

                const string sql = "INSERT INTO conversiondefinition (from_measurement_id, from_amount, to_measurement_id, to_amount) VALUES (@from_measurement_id, @from_amount, @to_measurement_id, @to_amount)";                
                var conn = new SqlConnection(Properties.Settings.Default.MyRecipeBookDbCS);
                var comm = new SqlCommand(sql, conn);

                comm.Parameters.Add("from_measurement_id", System.Data.SqlDbType.Int);
                comm.Parameters["from_measurement_id"].Value = fromType;

                comm.Parameters.Add("from_amount", System.Data.SqlDbType.Int);
                comm.Parameters["from_amount"].Value = fromAmount;

                comm.Parameters.Add("to_measurement_id", System.Data.SqlDbType.Int);
                comm.Parameters["to_measurement_id"].Value = toType;

                comm.Parameters.Add("to_amount", System.Data.SqlDbType.Int);
                comm.Parameters["to_amount"].Value = toAmount;

                conn.Open();

                var i = comm.ExecuteNonQuery();

                if (i != 1)
                {
                    return new Status { Result = StatusResult.Failed, Code = StatusCode.ConversionNotAdded };
                }

                conn.Close();

            }
            else if (status.Result == StatusResult.Success)
            {
                return new Status { Result = StatusResult.Failed, Code = StatusCode.ConversionAlreadyExists };
            }
            else
            {
                return new Status { Result = StatusResult.Failed, Code = StatusCode.Unknown };
            }

            return new Status { Result = StatusResult.Success, Code = StatusCode.ConversionAdded };
        }

        public Status Update(int fromType, float fromAmount, int toType, float toAmount)
        {
            return new Status { Result = StatusResult.Error, Code = StatusCode.NotImplemented };
        }

        public Status Remove(int fromType, int toType)
        {
            return new Status { Result = StatusResult.Error, Code = StatusCode.NotImplemented };
        }

        public Status GetConversion(int fromType, int toType, out Conversion conversion)
        {
            conversion = new Conversion{ Id = -1, FromId = fromType, FromName = "", FromAmount = -1f, ToId = -1, ToName ="", ToAmount = -1f};

            if (fromType == toType) return new Status { Result = StatusResult.Error, Code = StatusCode.ConversionTypesAreSame };
            if (fromType == 0) return new Status { Result = StatusResult.Error, Code = StatusCode.ConversionFromTypeIsInvalid };
            if (toType == 0) return new Status { Result = StatusResult.Error, Code = StatusCode.ConversionToTypeIsInvalid };

            try
            {

                const string sql = "SELECT id, from_measurement_id, from_measurement_name, from_amount, to_measurement_id, to_measurement_name, to_amount FROM conversions WHERE from_measurement_id=@from_measurement_id AND to_measurement_id=@to_measurement_id";
                var conn = new SqlConnection(Properties.Settings.Default.MyRecipeBookDbCS);
                var comm = new SqlCommand { CommandText = sql, Connection = conn };

                comm.Parameters.Add("from_measurement_id", System.Data.SqlDbType.Int);
                comm.Parameters["from_measurement_id"].Value = fromType;

                comm.Parameters.Add("to_measurement_id", System.Data.SqlDbType.Int);
                comm.Parameters["to_measurement_id"].Value = toType;

                conn.Open();

                var reader = comm.ExecuteReader();

                if (reader != null)
                {
                    if (reader.HasRows)
                    {
                        while (reader.Read())
                        {
                            conversion.Id = int.Parse(reader["id"].ToString());
                            conversion.FromId = int.Parse(reader["from_measurement_id"].ToString());
                            conversion.FromName = reader["from_measurement"].ToString();
                            conversion.FromAmount = float.Parse(reader["from_amount"].ToString());
                            conversion.ToId = int.Parse(reader["to_measurement_id"].ToString());
                            conversion.ToName = reader["to_measurement"].ToString();
                            conversion.ToAmount = float.Parse(reader["to_amount"].ToString());
                        }
                    }
                    else
                    {
                        return new Status { Result = StatusResult.Failed, Code = StatusCode.ConversionNotFound };
                    }

                    reader.Close();
                }
                conn.Close();
            }
            catch (Exception e)
            {
                LastException = e.Message;
                return new Status { Result = StatusResult.Exception, Code = StatusCode.Unknown };
            }

            return new Status { Result = StatusResult.Success, Code = StatusCode.ConversionFound };
        }

        public Status GetConversions(out List<Conversion> conversions)
        {
            conversions = new List<Conversion>();

            try
            {
                var conn = new SqlConnection(Properties.Settings.Default.MyRecipeBookDbCS);
                const string sql = "SELECT id, from_measurement_id, from_measurement_name, from_amount, to_measurement_id, to_measurement_name, to_amount FROM conversions ORDER BY id";
                var comm = new SqlCommand {CommandText = sql, Connection = conn};

                conn.Open();

                var reader = comm.ExecuteReader();

                if (reader != null)
                {
                    if (reader.HasRows)
                    {
                        while (reader.Read())
                        {
                            conversions.Add(new Conversion
                                                {
                                                    Id = int.Parse(reader["id"].ToString()),
                                                    FromId = int.Parse(reader["from_measurement_id"].ToString()),
                                                    FromName = reader["from_measurement_name"].ToString(),
                                                    FromAmount = float.Parse(reader["from_amount"].ToString()),
                                                    ToId = int.Parse(reader["to_measurement_id"].ToString()),
                                                    ToName = reader["to_measurement_name"].ToString(),
                                                    ToAmount = float.Parse(reader["to_amount"].ToString())
                                                });
                        }
                    }
                    else
                    {
                        return new Status { Result = StatusResult.Failed, Code = StatusCode.ConversionNotFound };
                    }

                    reader.Close();
                }
                conn.Close();
            }
            catch (Exception e)
            {
                LastException = e.Message;
                return new Status { Result = StatusResult.Exception, Code = StatusCode.Unknown };
            }

            return new Status { Result = StatusResult.Success, Code = StatusCode.ConversionFound };
        }
    }

    public class Conversion
    {
        public int Id { get; set; }
        public int FromId { get; set; }
        public string FromName { get; set; }
        public float FromAmount { get; set; }
        public int ToId { get; set; }
        public string ToName { get; set; }
        public float ToAmount { get; set; }

        public string NiceFrom
        {
            get
            {
                return string.Format("{0}{1}", FromAmount, FromName);
            }
        }

        public string NiceTo
        {
            get
            {
                return string.Format("{0}{1}", ToAmount, ToName);
            }
        }


        public override string ToString()
        {
            return FromAmount + " " + FromName + " = " + ToAmount + " " + ToName;
        }
    }
}
